package fileController

import (
	"encoding/json"
	"fmt"
	"mime"
	"mime/multipart"
	"myRbac/conf"
	"myRbac/models"
	"myRbac/utils"
	"myRbac/utils/jwt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/qiniu/go-sdk/v7/auth/qbox"
	"github.com/qiniu/go-sdk/v7/storage"
	"gorm.io/gorm"
)

type ImageController struct {
	Result
}

// @Summary 图片查询
// @Description 图片查询
// @Tags 图片管理
// @Accept json
// @Produce json
// @Param page query string false "页码"
// @Param pageSize query string false "尺寸"
// @Param name query string false "图片名"
// @Success 200 {object} models.ResultByPage[models.File] "查询成功"
// @Router /image [get]
// @Security JWT
func (i ImageController) QueryImages(ctx *gin.Context) {
	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(ctx.DefaultQuery("pageSize", "10"))
	nameStr := ctx.DefaultQuery("name", "")
	name := "%" + nameStr + "%"
	fileList := []models.File{}
	models.DB.Where("is_delete!=1 AND filename like (?)", name).Limit(pageSize).Offset(pageSize * (page - 1)).Order("id").Find(&fileList)
	var total int64
	// 查询条目
	models.DB.Table("files").Where("is_delete!=1 AND filename like (?)", name).Count(&total)
	// 返回值约束
	result := &models.ResultByPage[models.File]{
		Msg:      "ok",
		Code:     "200",
		Total:    total,
		Page:     page,
		PageSize: pageSize,
		Result:   fileList,
	}
	ctx.JSON(http.StatusOK, result)
}

// @Summary 图片新增
// @Description 图片新增
// @Tags 图片管理
// @Accept multipart/form-data
// @Produce json
// @Param imageInfo formData models.File false "文件信息"
// @Param file formData file false "文件"
// @Success 200 {object} models.AddResult "新增成功"
// @Success 400 {object} models.AddResult "新增失败"
// @Router /image [post]
// @Security JWT
func (i ImageController) AddImage(ctx *gin.Context) {
	var fileInfo models.File
	// 1.绑定一个file信息和一个文件
	if err := ctx.ShouldBindWith(&fileInfo, binding.FormMultipart); err != nil {
		i.DataNo(ctx)
		return
	}
	token, _ := ctx.Get("token")
	userId := token.(*jwt.MyClaims).User.Id

	// 2.将文件存到七牛云
	file, _ := ctx.FormFile("file")
	openFile, _ := file.Open()
	defer openFile.Close()
	fileUrl := i.UploadToQiniu(ctx, file, openFile, fmt.Sprint("rbac/IMG_", userId))
	if fileUrl == "" {
		i.Fail(ctx, "新增失败")
		return
	}
	// 3.将文件信息存入数据库
	// 解析字符串为json
	if err := json.Unmarshal([]byte(ctx.PostForm("info")), &fileInfo); err != nil {
		i.DataNo(ctx)
		return
	}
	// 3-1.文件加密（可以用于文件是否被篡改或者判断相同文件）
	fileInfo.Md5 = utils.Md5File(file)
	// 3-2.上传人Id
	fileInfo.Upper = userId
	// 3-3.新增时间
	fileInfo.UpLoadTime = utils.TimeFormatter(time.Now())
	// 3-4.设置path
	fileInfo.Path = fileUrl
	// 3-5.设置大小
	fileInfo.Size = file.Size
	// 3.6.设置文件类型
	fileInfo.ContentType = mime.TypeByExtension(file.Filename[strings.LastIndex(file.Filename, "."):])
	// 3.7.设置文件名
	if fileInfo.FileName == "" {
		fileInfo.FileName = file.Filename
	}
	if err := models.DB.Model(&models.File{}).Create(&fileInfo).Error; err != nil {
		i.Fail(ctx, "新增失败")
	} else {
		i.Success(ctx, "新增成功")
	}
}

// @Summary 图片修改
// @Description 图片修改
// @Tags 图片管理
// @Accept json
// @Produce json
// @Param imageInfo body models.File false "文件信息"
// @Success 200 {object} models.UpdateResult[models.File] "更新成功"
// @Router /image [put]
// @Security JWT
func (i ImageController) UpdateImage(ctx *gin.Context) {
	// 获取提交的角色修改信息
	var file models.File
	if err := ctx.ShouldBindJSON(&file); err != nil {
		i.DataNo(ctx)
		return
	}
	file_old := &models.File{}
	models.DB.First(&file_old, file.Id)
	if file.Id == 0 {
		i.Fail(ctx, "文件不存在")
		return
	}
	if result := models.DB.Model(&file_old).Updates(&file).Error; result != nil {
		i.Fail(ctx, "更新失败")
	} else {
		i.Success(ctx, "更新成功")
	}
}

// @Summary 图片删除
// @Description 图片删除
// @Tags 图片管理
// @Accept json
// @Produce json
// @Param fileIds body models.DeleteParams true "文件id合集"
// @Success 200 {object} models.DeleteResult "删除成功"
// @Router /image [delete]
// @Security JWT
func (i ImageController) DeleteImages(ctx *gin.Context) {
	fileIds := &models.DeleteParams{}
	if err := ctx.ShouldBindJSON(&fileIds); err != nil {
		i.DataNo(ctx)
	}
	// 1.从数据库中删掉图片
	if err2 := models.DB.Transaction(func(tx *gorm.DB) error {
		for j := 0; j < len(fileIds.Ids); j++ {
			file := &models.File{}
			tx.Model(&models.File{}).Where("id = ?", fileIds.Ids[j]).First(&file)
			if r := tx.Model(&file).Update("is_delete", 1).Error; r == nil {
				// 2.从七牛云中删掉图片
				i.DeleteFromQiniu(file.Path)
			} else {
				return r
			}
		}
		return nil
	}); err2 != nil {
		i.Fail(ctx, "删除失败")
	} else {
		i.Success(ctx, "删除成功")
	}
}

// 上下文，文件，打开的文件，前缀
func (i ImageController) UploadToQiniu(ctx *gin.Context, fileHeader *multipart.FileHeader, file multipart.File, prefix string) string {
	AccessKey, SerectKey, Bucket, _ := conf.Conf{}.LoadConfig()
	key := prefix + strconv.FormatInt(time.Now().UnixMilli(), 10) + fileHeader.Filename
	putPlicy := storage.PutPolicy{
		Scope:   Bucket,
		SaveKey: key,
	}
	mac := qbox.NewMac(AccessKey, SerectKey)
	upToken := putPlicy.UploadToken(mac)
	cfg := storage.Config{
		Zone:          &storage.ZoneHuanan,
		UseCdnDomains: false,
		UseHTTPS:      false,
	}
	putExtra := storage.PutExtra{
		Params: map[string]string{
			"x:name": fileHeader.Filename,
		},
	}
	formUploader := storage.NewFormUploader(&cfg)
	ret := storage.PutRet{}
	err := formUploader.PutWithoutKey(ctx, &ret, upToken, file, fileHeader.Size, &putExtra)
	if err != nil {
		return ""
	}
	return ret.Key
}

// 删除七牛云的某个资源
func (i ImageController) DeleteFromQiniu(key string) bool {
	AccessKey, SerectKey, Bucket, _ := conf.Conf{}.LoadConfig()
	mac := qbox.NewMac(AccessKey, SerectKey)
	cfg := storage.Config{
		UseHTTPS: false,
	}
	cfg.Region = &storage.ZoneHuanan
	bucketManager := storage.NewBucketManager(mac, &cfg)
	if err := bucketManager.Delete(Bucket, key); err != nil {
		return false
	} else {
		return true
	}
}
